/* this file defines tables that associates a number and an entry point to an user program. It also defines functions to access them.  */

#include "user_programs.h"

/* This array associates a program with an integer (the index) which will be used to retrieve the entry point in the second array. This integer is the program_id saved into the PCB */

static user_program programs[] = {
  { (uint32_t)init,
    "init",
    "First process started by the kernel.\nBe careful when editing its code.\n"
  },
  { (uint32_t)fibonacci,
    "fibonacci",
    "Compute the Fibonacci serie.\nUsage: fibonacci max_value\n"
  },
  { (uint32_t)increment,
    "increment", 
    "Counts from 0 to N.\nUsage: increment N\n"
  },
  { (uint32_t)scroller,   
    "scroller",
    "Scrolls a text on the LCD.\nUsage: scroller\n"
  },
  { (uint32_t)shell,
    "shell", 
    "Starts a shell that interprets commands and runs them.\nUsage: shell\n"
  },
  { (uint32_t)supervisor,
    "supervisor", 
    "Main program of the supervision example.\nIt starts a given number of children and supervises them.\nUsage: supervisor number_of_children\n"
  },
  { (uint32_t)supervision_child,
    "supervision_child",
    "Program run by the processes spawned by supervisor.\nIt has no real interest alone.\nIt sends a certain number of messages to its parents and exits.\n"
  },
  { (uint32_t)oom,
    "oom",
    "Creates processes until the system runs out of memory.\nUsage: oom\n"
  },
  { (uint32_t)some_task,
    "some_task",
    "Program run by the processes spawned by oom\nDoes nothing by itself.\n"
  },
  { (uint32_t)ring,
    "ring",
    "Main program of the ring program.\nCreates some ring_node processes and waits until its children are done.\nYou can specify both the number of children and the number of messages that will go through the ring.\nUsage: ring number_of_children number_of_messages\n"
  },
  { (uint32_t)ring_node,
    "ring_node", 
    "Program run by the processes spawned by ring.\nPasses the message it receives to its neighbor in the ring.\n"
  },
  { (uint32_t)dinner,
    "dinner", 
    "Starts an instance of the dining philosopher problem solved with a waiter solution.\nYou can specify the number of philosophers and the number of cycles each one has to go through.\nUsage: dinner number_of_philosopher number_of_cycles\n"
  },
  { (uint32_t)waiter,
    "waiter",
    "Waiter's program for the dining philosophers problem.\nArbitrates the requests from the philosophers about taking forks.\n" 
  },
  { (uint32_t)philosopher,
    "philosopher",
    "Philosopher's program for the dining philosophers problem.\nIt goes through a predefined number of cycles before leaving the table.\nA cycle is: thinking, taking left then right fork, eating, put forks back.\n"
  }
};


/* returns the program id of the program named program_name and its entry point */
int32_t get_program_information(const char* program_name,uint32_t* entry_point){
  int i;
  for(i=0;i < COUNT_UP && strcmp(program_name,programs[i].name) ;i++);
  // either i equals COUNT_UP and we didn't find the requested UP or i is the program id 
  if(i == COUNT_UP)
    return UNKNOWN_PROGRAM;   
  *entry_point = programs[i].entry_point;
  return i;
}

/* copy the program name of the program having program_id as id in a dynamically allocated on owner's behalf buffer. Returns NULL if the memory is full. */
char* get_program_name(int32_t program_id, int32_t owner){
  if(program_id < 0 || program_id >= COUNT_UP)
    return NULL;
  int32_t n = strlen(programs[program_id].name)+1;
  char* program_name = malloc(n*sizeof(char),owner);
  if(program_name == NULL)
    return NULL; //out of memory
  strncpy(program_name,programs[program_id].name,n);
  return program_name;
}

/* copy the program's help of the program having program_name as name in a dynamically allocated on owner's behalf buffer. Returns NULL if the memory is full. */
char* get_program_help(const char* program_name, int32_t owner){
  int i;
  for(i=0;i < COUNT_UP && strcmp(program_name,programs[i].name) ;i++);
  // either i equals COUNT_UP and we didn't find the requested UP or i is the program id 
  if(i == COUNT_UP)
    return NULL;   
  int32_t n = strlen(programs[i].help)+1;
  char* program_help = malloc(n*sizeof(char),owner);
  if(program_name == NULL)
    return NULL; //out of memory
  strncpy(program_help,programs[i].help,n);
  return program_help;
}
